package org.richin.servlet.util;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.PageContext;

import org.apache.log4j.Logger;
import org.richin.array.util.ArrayUtils;
import org.richin.collection.util.CollectionUtils;
import org.richin.lang.util.NumberUtils;
import org.richin.lang.util.StringUtils;
import org.richin.reflection.util.TypeClass;

/**
 * Request帮助类
 * 
 * @author Administrator
 * 
 */
public class RequestUtils {
	 /** 类似布尔值中的 {@code true}。 */
    public static final String ON = "on";

    /** 类似布尔值中的 {@code false}。 */
    public static final String OFF = "off";

    /** 类似布尔值中的 {@code true}。 */
    public static final String FLAG_TRUE = "1";

    /** 类似布尔值中的 {@code false}。 */
    public static final String FLAG_FALSE = "0";

    /** 布尔值中的 {@code true} 的字符串形式。 */
    public static final String TRUE = Boolean.toString(true);

    /** 布尔值中的 {@code false} 的字符串形式。 */
    public static final String FALSE = Boolean.toString(false);

    /** 表示一个空字符串的常量（表示为：<strong>&quot;&quot;</strong>）。 */
    public static final String EMPTY = "";

	private final static Logger log = Logger.getLogger(RequestUtils.class);

	/**
	 * 浏览器可接受的字符集
	 */
	public static final String ACCEPT_CHARSET = "Accept-Charset";

	/**
	 * 浏览器所希望的语言种类
	 */
	public static final String ACCEPT_LANGUAGE = "Accept-Language";

	/**
	 * 浏览器能够进行解码的数据编码方式
	 */
	public static final String ACCEPT_ENCODING = "Accept-Encoding";

	/**
	 * 浏览器可接受的MIME类型
	 */
	public static final String ACCEPT = "Accept";

	/**
	 * 浏览器类型
	 */
	public static final String USER_AGENT = "User-Agent";
	/** Regular expression that matches the HTML body end tag. */
	public static final String BODY_END_REGEX = "<\\s*/\\s*body[^>]*>";

	/** Regular expression that matches the HTML body start tag. */
	public static final String BODY_START_REGEX = "<\\s*body[^>]*>";
	/**
	 * 包含一个URL，用户从该URL代表的页面出发访问当前请求的页面
	 */
	public static final String REFERER = "Referer";
	/** Regex pattern that matches an end body tag. */
	private static final Pattern BODY_END_PATTERN = Pattern.compile(BODY_END_REGEX, Pattern.CASE_INSENSITIVE);

	/** Regex pattern that matches a start body tag. */
	private static final Pattern BODY_START_PATTERN = Pattern.compile(BODY_START_REGEX, Pattern.CASE_INSENSITIVE);

	/**
	 * Returns HTML encoded version of the specified String s.
	 * 
	 * @param s
	 *            String to be HTML encoded *
	 * @return HTML encoded String
	 */
	public static String htmlEncode(String s) {
		StringBuffer encodedString = new StringBuffer("");
		char[] chars = s.toCharArray();
		for (char c : chars) {
			if (c == '<') {
				encodedString.append("&lt;");
			} else if (c == '>') {
				encodedString.append("&gt;");
			} else {
				encodedString.append(c);
			}
		}
		return encodedString.toString();
	}

	/**
	 * Return the page resource path from the request. For example:
	 * <pre class="codeHtml">
	 * <span class="blue">http://www.mycorp.com/banking/secure/login.htm</span>  ->  <span class="red">/secure/login.htm</span> </pre>
	 *
	 * @param request the page servlet request
	 * @return the page resource path from the request
	 */
	public static String getResourcePath(HttpServletRequest request) {
		// Adapted from VelocityViewServlet.handleRequest() method:

		// If we get here from RequestDispatcher.include(), getServletPath()
		// will return the original (wrong) URI requested.  The following
		// special attribute holds the correct path.  See section 8.3 of the
		// Servlet 2.3 specification.

		String path = (String) request.getAttribute("javax.servlet.include.servlet_path");

		// Also take into account the PathInfo stated on
		// SRV.4.4 Request Path Elements.
		String info = (String) request.getAttribute("javax.servlet.include.path_info");

		if (path == null) {
			path = request.getServletPath();
			info = request.getPathInfo();
		}

		if (info != null) {
			path += info;
		}

		return path;
	}

	/**
	 * Convenience method to get the application's URL based on request
	 * variables.
	 * 
	 * @param request the current request
	 * @return URL to application
	 */
	public static String getAppURL(HttpServletRequest request) {
		StringBuffer url = new StringBuffer();
		int port = request.getServerPort();
		if (port < 0) {
			port = 80; // Work around java.net.URL bug
		}
		String scheme = request.getScheme();
		url.append(scheme);
		url.append("://");
		url.append(request.getServerName());
		if ((scheme.equals("http") && (port != 80)) || (scheme.equals("https") && (port != 443))) {
			url.append(':');
			url.append(port);
		}
		url.append(request.getContextPath());
		return url.toString();
	}

	/** 
	* 获得客户端真实IP地址 
	* 
	* @param request 
	* @return 
	*/
	public static String getIpAddr(HttpServletRequest request) {
		String ip = request.getHeader("X-Forwarded-For");
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("WL-Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("HTTP_CLIENT_IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("HTTP_X_FORWARDED_FOR");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getRemoteAddr();
		}

		return ip;
	}

	/**
	 * 获取请求的URL路径报告请求差数
	 * @param request
	 * @return
	 */
	public static String requestURL(HttpServletRequest request) {
		Map<String, String[]> queryMap = request.getParameterMap();
		StringBuffer queryString = new StringBuffer(request.getRequestURL());

		boolean flag = true;
		for (Map.Entry<String, String[]> params : queryMap.entrySet()) {
			for (String value : params.getValue()) {
				if (flag) {
					queryString.append("?" + params.getKey() + "=" + value);
					flag = false;
				} else
					queryString.append("&" + params.getKey() + "=" + value);

			}
		}
		return queryString.toString();
	}

	/**  
	 * 取得当前http地址  
	 * @param request  
	 * @return  
	 * Date: 2008-12-1 下午02:59:03  
	 */
	public static String getCurrentHttpURL(HttpServletRequest request) {

		StringBuilder urlBuilder = new StringBuilder();
		urlBuilder.append(request.getScheme()).append("://");
		urlBuilder.append(request.getServerName());
		urlBuilder.append(request.getHeader("host")).append(":");
		urlBuilder.append(request.getServerPort());
		urlBuilder.append(request.getContextPath()).append("/");

		String httpAddr = urlBuilder.toString();
		urlBuilder = null;
		return httpAddr;
	}

	public static String getCompleteURL(HttpServletRequest request) {
		return new StringBuilder(getCurrentHttpURL(request)).append(request.getServletPath()).append("?").append(
				request.getQueryString()).toString();
	}

	public static URL absoluteURL(HttpServletRequest request, String path) throws MalformedURLException {

		return (new URL(serverURL(request), request.getContextPath() + path));

	}

	public static URL serverURL(HttpServletRequest request) throws MalformedURLException {

		StringBuffer url = requestToServerStringBuffer(request);
		return (new URL(url.toString()));

	}

	public static StringBuffer requestToServerStringBuffer(HttpServletRequest request) {

		return createServerStringBuffer(request.getScheme(), request.getServerName(), request.getServerPort());

	}

	public static StringBuffer createServerStringBuffer(String scheme, String server, int port) {

		StringBuffer url = new StringBuffer();
		if (port < 0) {
			port = 80; // Work around java.net.URL bug
		}
		url.append(scheme);
		url.append("://");
		url.append(server);
		if ((scheme.equals("http") && (port != 80)) || (scheme.equals("https") && (port != 443))) {
			url.append(':');
			url.append(port);
		}
		return url;

	}

	/**     
	 *  Write the HTML base tag to support servlet forward calling relative path     
	 *  changed problems.     *     
	 *  Base is used to ensure that your document's relative links are associated     
	 *  with the proper document path. The href specifies the document's     
	 *  reference URL for associating relative URLs with the proper document     
	 *  path. This element may only be used within the HEAD tag. Example: <BASE     
	 *  HREF="http://www.sample.com/hello.htm">     *     
	 *  @param pageContext     
	 * the PageContext of the jsp page object     */
	public static void writeHtmlBase(PageContext pageContext) {
		HttpServletRequest request = (HttpServletRequest) pageContext.getRequest();
		StringBuffer buf = new StringBuffer("<base href=\"");
		buf.append(request.getScheme());
		buf.append("://");
		buf.append(request.getServerName());
		buf.append(":");
		buf.append(request.getServerPort());
		buf.append(request.getRequestURI());
		buf.append("\">");
		JspWriter out = pageContext.getOut();
		try {
			out.write(buf.toString());
		} catch (java.io.IOException e) {
		}
	}

	@SuppressWarnings("unchecked")
	public static String getRequestParameters(HttpServletRequest request) {
		StringBuffer sb = new StringBuffer("");
		Map map = request.getParameterMap();
		Set entrySet = map.entrySet();
		Iterator iterator = entrySet.iterator();
		while (iterator.hasNext()) {
			Map.Entry entry = (Map.Entry) iterator.next();
			if (entry.getValue() instanceof List) {
				List valueList = (List) entry.getValue();
				for (int i = 0; i < valueList.size(); i++) {
					if (sb.length() > 0) {
						sb.append("&");
					}
					try {
						sb.append(URLEncoder.encode((String) entry.getKey(), "UTF-8"));
						sb.append("=");
						sb.append(URLEncoder.encode((String) valueList.get(i), "UTF-8"));
					} catch (UnsupportedEncodingException uee) {
						log.error("UTF-8 is not a supported encoding - that is quite wierd", uee);
					}
				}
			} else {
				log.debug("not adding entry: " + entry.getKey() + "=" + entry.getValue().toString());
			}
		}
		return sb.toString();
	}

	/**     
	 *  Get the base path of this request.     
	 * @param request -HttpServletRequest     
	 *  @return String - the base path, eg: http://www.abc.com:8000/someApp/     */
	public static String getBasePath(HttpServletRequest request) {
		String path = request.getContextPath();
		String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path
				+ "/";
		return basePath;
	}

	/**     
	 *  Get the current page's full path of this request. 获取当前页的完整访问 URL 路径.        
	 *  @param request -HttpServletRequest     
	 *  @return String - the full url path, eg:     
	 *  http://www.abc.com:8000/someApp/index.jsp?param=abc     */
	public static String getFullRequestURL(HttpServletRequest request) {
		StringBuffer url = request.getRequestURL();
		String qString = request.getQueryString();
		if (qString != null) {
			url.append('?');
			url.append(qString);
		}
		return url.toString();
	}

	/**     
	 * Get the current page's full path of this request. 获取当前页的完整访问 URI 路径.        
	 * @param request -HttpServletRequest     
	 * @return String - the full uri path, eg: /someApp/index.jsp?param=abc     */
	public static String getFullRequestURI(HttpServletRequest request) {
		StringBuffer url = new StringBuffer(request.getRequestURI());
		String qString = request.getQueryString();
		if (qString != null) {
			url.append('?');
			url.append(qString);
		}
		return url.toString();
	}

	public static String getServletDir(HttpServletRequest request) {
		String servletpath = request.getServletPath();
		if (null != servletpath) {
			int lastindex = servletpath.lastIndexOf("/");

			if (-1 != lastindex)
				return servletpath.substring(0, lastindex + 1);
		}
		return "";
	}

	/**
	 * 获取当前请求页面
	 */
	public static String getPageName(HttpServletRequest request) {
		// 获取请求路径
		String uri = request.getRequestURI();
		return uri.substring(uri.lastIndexOf("/") + 1).toLowerCase();
	}

	/**
	 * 判断是否来自搜索引擎链接
	 * @return 是否来自搜索引擎链接
	 */
	public static boolean isSearchEnginesGet(HttpServletRequest request) {
		if (getUrlReferrer(request).equals(""))
			return false;
		String[] searchEngine = { "google", "yahoo", "msn", "baidu", "sogou", "sohu", "sina", "163", "lycos", "tom",
				"yisou", "iask", "soso", "gougou", "zhongsou" };
		for (String string : searchEngine) {
			if (string.indexOf(getUrlReferrer(request)) >= 0)
				return true;
		}
		return false;
	}

	/**
	 * 判断当前访问是否来自浏览器软件
	 * @return 当前访问是否来自浏览器软件
	 */
	public static boolean isBrowserGet(HttpServletRequest request) {
		String[] browserName = { "ie", "opera", "netscape", "mozilla", "konqueror", "firefox" };
		String curBrower = getHeader(request, USER_AGENT).toLowerCase();
		for (String string : browserName) {
			if (curBrower.indexOf(string) >= 0)
				return true;
		}
		return false;
	}

	/**
	 * 得到当前完整主机头
	 * @return
	 */
	public static String getCurrentFullHost(HttpServletRequest request) {
		return request.getRemoteHost() + ":" + request.getRemotePort();
	}

	/**
	 * 得到主机头
	 * @return
	 */
	public static String getHost(HttpServletRequest request) {
		return request.getRemoteHost();
	}

	/**
	 * 返回指定的请求头信息
	 * @param name 变量名
	 * @return 信息
	 */
	public static String getHeader(HttpServletRequest request, String name) {
		if (request.getHeader(name) == null)
			return "";
		return request.getHeader(name);
	}

	/**
	 * 判断当前页面是否接收到了Post请求
	 * @return 是否接收到Post请求
	 */
	public static boolean isPost(HttpServletRequest request) {
		return request.getMethod().equalsIgnoreCase("POST");
	}

	/**
	 * 判断当前页面是否接收到了Get请求
	 * @return 是否接收到Get请求
	 */
	public static boolean isGet(HttpServletRequest request) {
		return request.getMethod().equalsIgnoreCase("GET");
	}

	/**
	 * 返回上一个页面的地址
	 * @return 上一个页面地址
	 */
	public static String getUrlReferrer(HttpServletRequest request) {
		return getHeader(request, REFERER);
	}

	public static void setSessionValue(HttpServletRequest request, String key, Object value) {

		HttpSession session = request.getSession(true);
		session.setAttribute(key, value);
	}

	/**
	  * Appends a request parameter to the given URL.<p>
	  *
	  * This method takes care about the adding the parameter as an additional
	  * parameter (appending <code>&param=value</code>) or as the first parameter
	  * (appending <code>?param=value</code>).<p>
	  *
	  * @param url the URL where to append the parameter to
	  * @param paramName the paramter name to append
	  * @param paramValue the parameter value to append
	  *
	  * @return the URL with the given parameter appended
	  */
	public static String appendParameter(String url, String paramName, String paramValue) {

		if (org.apache.commons.lang.StringUtils.isEmpty(url))
			return null;
		int pos = url.indexOf('?');
		StringBuffer result = new StringBuffer(256);
		result.append(url);
		if (pos >= 0) {
			// url already has parameters
			result.append('&');
		} else {
			// url does not have parameters
			result.append('?');
		}
		result.append(paramName);
		result.append('=');
		result.append(paramValue);
		return result.toString();
	}

	/**
	 * Appends a map of request parameters to the given URL.<p>
	 *
	 * The map can cointains values of <code>String[]</code> or
	 * simple <code>String</code> values.<p>
	 *
	 * This method takes care about the adding the parameter as an additional
	 * parameter (appending <code>&param=value</code>) or as the first parameter
	 * (appending <code>?param=value</code>).<p>
	 *
	 * @param url the URL where to append the parameter to
	 * @param params the paramters to append
	 * @param encode if <code>true</code>, the parameter values are encoded before they are appended
	 *
	 * @return the URL with the given parameter appended
	 */
	public static String appendParameters(String url, Map params, boolean encode) {

		if (org.apache.commons.lang.StringUtils.isEmpty(url))
			return null;
		if ((params == null) || params.isEmpty())
			return url;
		int pos = url.indexOf('?');
		StringBuffer result = new StringBuffer(256);
		result.append(url);
		if (pos >= 0) {
			// url already has parameters
			result.append('&');
		} else {
			// url does not have parameters
			result.append('?');
		}
		// ensure all values are of type String[]
		Map newParams = createParameterMap(params);
		Iterator i = newParams.keySet().iterator();
		while (i.hasNext()) {
			String key = (String) i.next();
			Object value = newParams.get(key);
			String[] values = (String[]) value;
			for (int j = 0; j < values.length; j++) {
				String strValue = values[j];
				if (encode) {
					strValue = Encoder.encode(strValue);
				}
				result.append(key);
				result.append('=');
				result.append(strValue);
				if ((j + 1) < values.length) {
					result.append('&');
				}
			}
			if (i.hasNext()) {
				result.append('&');
			}
		}
		return result.toString();
	}

	/**
	 * Returns all parameters of the given request
	 * as a request parameter URL String, that is in the form <code>key1=value1&key2=value2</code> etc.
	 *
	 * The result will be encoded using the <code>{@link Encoder#encode(String)}</code> function.<p>
	 *
	 * @param req the request to read the parameters from
	 *
	 * @return all initialized parameters of the given request as request parameter URL String
	 */
	public static String encodeParams(HttpServletRequest req) {

		StringBuffer result = new StringBuffer(512);
		Map params = req.getParameterMap();
		Iterator i = params.keySet().iterator();
		while (i.hasNext()) {
			String param = (String) i.next();
			String[] values = (String[]) params.get(param);
			for (int j = 0; j < values.length; j++) {
				result.append(param);
				result.append("=");
				result.append(Encoder.encode(values[j]));
				if ((j + 1) < values.length) {
					result.append("&");
				}
			}
			if (i.hasNext()) {
				result.append("&");
			}
		}
		return Encoder.encode(result.toString());
	}

	/**
	 * Encodes the given uri, with all parameters from the given request appended.<p>
	 *
	 * The result will be encoded using the <code>{@link Encoder#encode(String)}</code> function.<p>
	 *
	 * @param req the request where to read the parameters from
	 * @param uri the uri to encode
	 * @return the encoded uri, with all parameters from the given request appended
	 */
	public static String encodeParamsWithUri(String uri, HttpServletRequest req) {

		String result;
		String params = encodeParams(req);
		if (org.apache.commons.lang.StringUtils.isNotEmpty(params)) {
			result = Encoder.encode(uri + "?") + params;
		} else {
			result = Encoder.encode(uri);
		}
		return result;
	}

	/**
	 * Extracts the content of a &lt;body&gt tag in a HTML page.<p>
	 *
	 * This method should be pretty robust and work even if the input HTML does not contains
	 * a valid body tag.<p>
	 *
	 * @param content the content to extract the body from
	 * @return the extracted body tag content
	 */
	public static String extractHtmlBody(String content) {

		Matcher startMatcher = BODY_START_PATTERN.matcher(content);
		Matcher endMatcher = BODY_END_PATTERN.matcher(content);

		int start = 0;
		int end = content.length();

		if (startMatcher.find()) {
			start = startMatcher.end();
		}

		if (endMatcher.find(start)) {
			end = endMatcher.start();
		}

		return content.substring(start, end);
	}

	/**
	 * Creates a valid request parameter map from the given map,
	 * most notably changing the values form <code>String</code>
	 * to <code>String[]</code> if required.<p>
	 *
	 * If the given parameter map is <code>null</code>, then <code>null</code> is returned.<p>
	 *
	 * @param params the map of parameters to create a parameter map from
	 * @return the created parameter map, all values will be instances of <code>String[]</code>
	 */
	public static Map createParameterMap(Map params) {

		if (params == null)
			return null;
		HashMap result = new HashMap();
		Iterator i = params.keySet().iterator();
		while (i.hasNext()) {
			String key = i.next().toString();
			Object values = params.get(key);
			if (values instanceof String[]) {
				result.put(key, values);
			} else {
				result.put(key, new String[] { values.toString() });
			}
		}
		return result;
	}

	/**
	 * Parses the parameters of the given request query part and creaes a parameter map out of them.<p>
	 *
	 * Please note: This does not parse a full request URI/URL, only the query part that
	 * starts after the "?". For example, in the URI <code>/system/index.html?a=b&amp;c=d</code>,
	 * the query part is <code>a=b&amp;c=d</code>.<p>
	 *
	 * If the given String is empty, an empty map is returned.<p>
	 *
	 * @param query the query to parse
	 * @return the parameter map created from the query
	 */
	public static Map<String, String[]> createParameterMap(String query) {

		if (org.apache.commons.lang.StringUtils.isEmpty(query))
			// empty query
			return new HashMap<String, String[]>();
		if (query.charAt(0) == '?') {
			// remove leading '?' if required
			query = query.substring(1);
		}
		HashMap<String, String[]> parameters = new HashMap<String, String[]>();
		// cut along the different parameters
		String[] params = org.apache.commons.lang.StringUtils.split(query, '&');
		for (String element : params) {
			String key = null;
			String value = null;
			// get key and value, separated by a '='
			int pos = element.indexOf('=');
			if (pos > 0) {
				key = element.substring(0, pos);
				value = element.substring(pos + 1);
			} else if (pos < 0) {
				key = element;
				value = "";
			}
			// now make sure the values are of type String[]
			if (key != null) {
				String[] values = parameters.get(key);
				if (values == null) {
					// this is the first value, create new array
					values = new String[] { value };
				} else {
					// append to the existing value array
					String[] copy = new String[values.length + 1];
					System.arraycopy(values, 0, copy, 0, values.length);
					copy[copy.length - 1] = value;
					values = copy;
				}
				parameters.put(key, values);
			}
		}
		return parameters;
	}

	@SuppressWarnings("unchecked")
	public static void requestHeadersToLog(HttpServletRequest request) {
		// Print Request Parameters
		log.debug("Printing Request Headers");
		Enumeration<String> enums = request.getHeaderNames();
		String s;
		Object header;
		while (enums.hasMoreElements()) {
			s = enums.nextElement();
			header = request.getHeader(s);
			log.debug(s + ":\n" + header);
		}

	}// requestHeadersToLog()

	public static void debugRequestToLog(HttpServletRequest request) {
		requestToStringToLog(request);
		requestRemoteInfoToLog(request);
		// requestInputStreamToLog( request );
		requestHeadersToLog(request);
		requestParametersToLog(request);
		requestAttributesToLog(request);
	}// debugRequestToLog()

	public static void requestToStringToLog(HttpServletRequest request) {
		// Print Request remote information
		log.debug("Printing Request toString() info");
		log.debug("Request toString():" + StringUtils.getToString(request));

	}// requestToStringToLog()

	public static void requestRemoteInfoToLog(HttpServletRequest request) {
		// Print Request remote information
		log.debug("Printing Request remote client or last proxy information");
		log.debug("Request RemoteAddr:" + getIpAddr(request));
		log.debug("Request RemoteHost:" + request.getRemoteHost());
		//log.debug( "Request RemotePort:" + request.getRemotePort() );

	}// requestInputStreamToLog()

	@SuppressWarnings("unchecked")
	public static void requestParametersToLog(HttpServletRequest request) {
		// Print Request Parameters
		log.debug("Printing Request Parameters");
		Enumeration<String> enums = request.getParameterNames();
		String s;
		Object attribute;
		while (enums.hasMoreElements()) {
			s = enums.nextElement();
			attribute = request.getParameter(s);
			log.debug(s + ":\n" + attribute);
		}

	}// requestParametersToLog()

	@SuppressWarnings("unchecked")
	public static void requestAttributesToLog(HttpServletRequest request) {
		log.debug("Printing Request Attributes");
		// Print Request Attributes
		Enumeration<String> enums = null;
		String s;
		Object attribute;
		enums = request.getAttributeNames();
		while (enums.hasMoreElements()) {
			s = enums.nextElement();
			attribute = request.getAttribute(s);
			log.debug(s + ":\n" + attribute);
		}

	}// requestAttributesToLog()

	@SuppressWarnings("unchecked")
	public static void sessionAttributesToLog(HttpSession session) {
		// Print Session Attributes
		Enumeration<String> enums = null;
		String s;
		Object attribute;
		enums = session.getAttributeNames();
		while (enums.hasMoreElements()) {
			s = enums.nextElement();
			attribute = session.getAttribute(s);
			log.debug(s + ":\n" + attribute);
		}

	}// sessionAttributesToLog()

	/**
	 * Retrieves the current request servlet path.
	 * Deals with differences between servlet specs (2.2 vs 2.3+)
	 *
	 * @param request the request
	 * @return the servlet path
	 */
	public static String getServletPath(HttpServletRequest request) {
		String servletPath = request.getServletPath();

		if (null != servletPath && !"".equals(servletPath)) {
			return servletPath;
		}

		String requestUri = request.getRequestURI();
		int startIndex = request.getContextPath().equals("") ? 0 : request.getContextPath().length();
		int endIndex = request.getPathInfo() == null ? requestUri.length() : requestUri.lastIndexOf(request
				.getPathInfo());

		if (startIndex > endIndex) { // this should not happen
			endIndex = startIndex;
		}

		return requestUri.substring(startIndex, endIndex);
	}

	public void getss(HttpServletRequest request) {
		Enumeration<String> enumeration = request.getAttributeNames();
		while (enumeration.hasMoreElements()) {
			String key = (String) enumeration.nextElement();
			log.debug("key:" + key + "=>value:" + request.getAttribute(key));
		}
	}

	/**
	 * 输入网址获得网页
	 *
	 * @param path
	 * @return
	 */
	public static String getHtml(String path) {
		try {
			URL url = new URL(path);
			URLConnection conn = url.openConnection();
			BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
			StringBuffer sb = new StringBuffer();
			String s = null;
			while ((s = br.readLine()) != null) {
				sb.append(s);
				sb.append('\n');
			}
			br.close();
			return sb.toString();
		} catch (MalformedURLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return null;
		}
		return null;
	}

	/**
	 * 取得Web的根路径
	 *
	 * @return
	 */
	public static String getWebRoot() {
		String path = RequestUtils.class.getClassLoader().getResource("\\").getPath();
		path = path.substring(1, path.indexOf("WEB-INF"));

		return path;
	}

	/**
	 * 从 {@code javax.servlet.http.HttpServletRequest} 的请求中获取给定参数名称的参数的值。
	 * 若该参数没被传递或没被赋值时返回空字符串（&quot;&quot;）。
	 *
	 * @param request 当前Web应用的 {@code HttpServletRequest} 对象。
	 * @param name 获取的参数的名称。
	 * @return 返回给定参数名称的参数的值。
	 * @see #getParameter(HttpServletRequest, String, String)
	 */
	public static String getParameter(HttpServletRequest request, String name) {
		return getParameter(request, name, StringUtils.EMPTY);
	}

	/**
	 * 从 {@code javax.servlet.http.HttpServletRequest} 的请求中获取给定参数名称的参数的值。
	 *
	 * @param request 当前Web应用的 {@code HttpServletRequest} 对象。
	 * @param name 获取的参数的名称。
	 * @param defaultValue 该参数没被传递或没被赋值时返回的默认值。
	 * @return 返回给定参数名称的参数的值。
	 */
	public static String getParameter(HttpServletRequest request, String name, String defaultValue) {
		if (StringUtils.isNullStr(name))
			return defaultValue;
		String value = request.getParameter(name);
		return value == null ? defaultValue : value.trim();
	}

	/**
	 * 从 {@code javax.servlet.http.HttpServletRequest} 的请求中获取给定参数名称的参数的值。
	 * 该参数所获得的值是一个数组，相当于接收的是 {@code CheckBox} 或者 {@code ComboBox} 的值。
	 *
	 * @param request 当前Web应用的 {@code HttpServletRequest} 请求对象。
	 * @param name 获取的参数的名称。
	 * @return 返回给定参数名称的参数的值。
	 */
	public static String[] getParameters(HttpServletRequest request, String name) {
		return getParameters(request, name, new String[] {});
	}

	/**
	 * 从 {@code javax.servlet.http.HttpServletRequest} 的请求中获取给定参数名称的参数的值。
	 * 该参数所获得的值是一个数组，相当于接收的是 {@code CheckBox} 或者 {@code ComboBox} 的值。
	 *
	 * @param request 当前Web应用的 {@code HttpServletRequest} 请求对象。
	 * @param name 获取的参数的名称。
	 * @param defaults 该参数没被传递或没被赋值时返回的默认值。
	 * @return 返回给定参数名称的参数的值。
	 */
	public static String[] getParameters(HttpServletRequest request, String name, String[] defaults) {
		if (StringUtils.isNullStr(name))
			return defaults;
		String[] values = request.getParameterValues(name);
		return values == null || values.length == 0 ? defaults : values;
	}

	/**
	 * 从 {@code javax.servlet.http.HttpServletRequest} 的请求中获取给定参数名称的参数的值。
	 * 该参数所获得的值是一组 {@code java.util.List&lt;String&gt;} 封装的值，相当于接收的是
	 * {@code CheckBox} 或者 {@code ComboBox} 的值。若该参数没被传递或没被赋值时返回 0 长度的
	 * {@code java.util.List&lt;String&gt;}。
	 *
	 * @param request 当前Web应用的 {@code HttpServletRequest} 请求对象。
	 * @param name 获取的参数的名称。
	 * @return 返回给定参数名称的参数的值。
	 */
	public static List<String> getParametersByList(HttpServletRequest request, String name) {
		return getParametersByList(request, name, new LinkedList<String>());
	}

	/**
	 * 从 {@code javax.servlet.http.HttpServletRequest} 的请求中获取给定参数名称的参数的值。
	 * 该参数所获得的值是一组 {@code java.util.List&lt;String&gt;} 封装的值，相当于接收的是
	 * {@code CheckBox} 或者 {@code ComboBox} 的值。
	 *
	 * @param request 当前Web应用的 {@code HttpServletRequest} 请求对象。
	 * @param name 获取的参数的名称。
	 * @param defaultList 该参数没被传递或没被赋值时返回的默认值。
	 * @return 返回给定参数名称的参数的值。
	 */
	public static List<String> getParametersByList(HttpServletRequest request, String name, List<String> defaultList) {
		if (StringUtils.isNullStr(name))
			return defaultList;
		String[] values = request.getParameterValues(name);
		if (values == null || values.length == 0)
			return defaultList;
		else {
			List<String> list = new LinkedList<String>();
			for (String val : values) {
				list.add(val);
			}
			return list;
		}
	}

	/**
	 * 从 {@code javax.servlet.http.HttpServletRequest} 的请求中获取给定参数名称的
	 * {@code java.math.BigDecimal} 类型的参数值。 若该参数没被传递或没被赋值时返回
	 * {@code java.math.BigDecimal} 类型的 0。
	 *
	 * @param request 当前Web应用的 {@code HttpServletRequest} 对象。
	 * @param name 获取的参数的名称。
	 * @return 返回给定参数名称的 {@code java.math.BigDecimal} 类型的参数值
	 * @see #getBigDecimalParameter(HttpServletRequest, String, BigDecimal)
	 */
	public static BigDecimal getBigDecimalParameter(HttpServletRequest request, String name) {
		return getBigDecimalParameter(request, name, NumberUtils.parseDecimal("0"));
	}

	/**
	 * 从 {@code javax.servlet.http.HttpServletRequest} 的请求中获取给定参数名称的
	 * {@code java.math.BigDecimal} 类型的参数值。
	 *
	 * @param request 当前Web应用的 {@code HttpServletRequest} 对象。
	 * @param name 获取的参数的名称。
	 * @param defaultValue 该参数没被传递或没被赋值时返回的默认值。
	 * @return 返回给定参数名称的 {@code java.math.BigDecimal} 类型的参数值
	 */
	public static BigDecimal getBigDecimalParameter(HttpServletRequest request, String name, BigDecimal defaultValue) {
		return NumberUtils.parseDecimal(getParameter(request, name), defaultValue);
	}

	/**
	 * 从 {@code javax.servlet.http.HttpServletRequest} 的请求中获取给定参数名称的布尔值。
	 * 若该参数没被传递或没被赋值时默认返回 {@code false}。
	 *
	 * @param request 当前Web应用的 {@code HttpServletRequest} 对象。
	 * @param name 获取的参数的名称。
	 * @return 返回给定参数名称的布尔值。
	 * @see #getBoolParameter(HttpServletRequest, String, boolean)
	 */
	public static boolean getBoolParameter(HttpServletRequest request, String name) {
		return getBoolParameter(request, name, Boolean.FALSE);
	}

	/**
	 * 从 {@code javax.servlet.http.HttpServletRequest} 的请求中获取给定参数名称的布尔值。
	 *
	 * @param request 当前Web应用的 {@code HttpServletRequest} 对象。
	 * @param name 获取的参数的名称。
	 * @param defaultValue 该参数没被传递或没被赋值时返回的默认值。
	 * @return 返回给定参数名称的布尔值。
	 */
	public static boolean getBoolParameter(HttpServletRequest request, String name, boolean defaultValue) {
		String value = getParameter(request, name).trim();
		if (StringUtils.isNullStr(value))
			return defaultValue;
		if (TRUE.equals(value) || ON.equals(value) || FLAG_TRUE.equals(value))
			return Boolean.TRUE;
		else if (FALSE.equals(value) || OFF.equals(value) || FLAG_FALSE.equals(value))
			return Boolean.FALSE;
		return defaultValue;
	}

	/**
	 * 从 {@code javax.servlet.http.HttpServletRequest} 的请求中获取给定参数名称的
	 * {@code byte} 类型的参数值。若该参数没被传递或没被赋值时返回 {@code byte} 类型的 0。
	 *
	 * @param request 当前Web应用的 {@code HttpServletRequest} 对象。
	 * @param name 获取的参数的名称。
	 * @return 返回给定参数名称的 {@code byte} 类型的参数值
	 * @see #getByteParameter(HttpServletRequest, String, byte)
	 */
	public static byte getByteParameter(HttpServletRequest request, String name) {
		return getByteParameter(request, name, (byte) 0);
	}

	/**
	 * 从 {@code javax.servlet.http.HttpServletRequest} 的请求中获取给定参数名称的
	 * {@code byte} 类型的参数值。
	 *
	 * @param request 当前Web应用的 {@code HttpServletRequest} 对象。
	 * @param name 获取的参数的名称。
	 * @param defaultValue 该参数没被传递或没被赋值时返回的默认值。
	 * @return 返回给定参数名称的 {@code byte} 类型的参数值
	 */
	public static byte getByteParameter(HttpServletRequest request, String name, byte defaultValue) {
		return NumberUtils.parseByte(getParameter(request, name), defaultValue);
	}

	/**
	 * 从 {@code javax.servlet.http.HttpServletRequest} 的请求中获取给定参数名称的
	 * {@code double} 类型的参数值。若该参数没被传递或没被赋值时返回 {@code double} 类型的 0.0d。
	 *
	 * @param request 当前Web应用的 {@code HttpServletRequest} 对象。
	 * @param name 获取的参数的名称。
	 * @return 返回给定参数名称的 {@code double} 类型的参数值
	 * @see #getDoubleParameter(HttpServletRequest, String, double)
	 */
	public static double getDoubleParameter(HttpServletRequest request, String name) {
		return getDoubleParameter(request, name, 0.0d);
	}

	/**
	 * 从 {@code javax.servlet.http.HttpServletRequest} 的请求中获取给定参数名称的
	 * {@code double} 类型的参数值。
	 *
	 * @param request 当前Web应用的 {@code HttpServletRequest} 对象。
	 * @param name 获取的参数的名称。
	 * @param defaultValue 该参数没被传递或没被赋值时返回的默认值。
	 * @return 返回给定参数名称的 {@code double} 类型的参数值
	 */
	public static double getDoubleParameter(HttpServletRequest request, String name, double defaultValue) {
		return NumberUtils.parseDouble(getParameter(request, name), defaultValue);
	}

	/**
	 * 从 {@code javax.servlet.http.HttpServletRequest} 的请求中获取给定参数名称的
	 * {@code float} 类型的参数值。若该参数没被传递或没被赋值时返回 {@code float} 类型的 0.0f。
	 *
	 * @param request 当前Web应用的 {@code HttpServletRequest} 对象。
	 * @param name 获取的参数的名称。
	 * @return 返回给定参数名称的 {@code float} 类型的参数值
	 * @see #getFloatParameter(HttpServletRequest, String, float)
	 */
	public static float getFloatParameter(HttpServletRequest request, String name) {
		return getFloatParameter(request, name, 0.0f);
	}

	/**
	 * 从 {@code javax.servlet.http.HttpServletRequest} 的请求中获取给定参数名称的
	 * {@code float} 类型的参数值。
	 *
	 * @param request 当前Web应用的 {@code HttpServletRequest} 对象。
	 * @param name 获取的参数的名称。
	 * @param defaultValue 该参数没被传递或没被赋值时返回的默认值。
	 * @return 返回给定参数名称的 {@code float} 类型的参数值
	 */
	public static float getFloatParameter(HttpServletRequest request, String name, float defaultValue) {
		return NumberUtils.parseFloat(getParameter(request, name), defaultValue);
	}

	/**
	 * 从 {@code javax.servlet.http.HttpServletRequest} 的请求中获取给定参数名称的 {@code int}
	 * 类型的参数值。若该参数没被传递或没被赋值时返回 {@code int} 类型的 0。
	 *
	 * @param request 当前Web应用的 {@code HttpServletRequest} 对象。
	 * @param name 获取的参数的名称。
	 * @return 返回给定参数名称的 {@code int} 类型的参数值
	 * @see #getIntParameter(HttpServletRequest, String, int)
	 */
	public static int getIntParameter(HttpServletRequest request, String name) {
		return getIntParameter(request, name, 0);
	}

	/**
	 * 从 {@code javax.servlet.http.HttpServletRequest} 的请求中获取给定参数名称的 {@code int}
	 * 类型的参数值。
	 *
	 * @param request 当前Web应用的 {@code HttpServletRequest} 对象。
	 * @param name 获取的参数的名称。
	 * @param defaultValue 该参数没被传递或没被赋值时返回的默认值。
	 * @return 返回给定参数名称的 {@code int} 类型的参数值
	 */
	public static int getIntParameter(HttpServletRequest request, String name, int defaultValue) {
		return NumberUtils.parseInt(getParameter(request, name), defaultValue);
	}

	/**
	 * 从 {@code javax.servlet.http.HttpServletRequest} 的请求中获取给定参数名称的
	 * {@code long} 类型的参数值。若该参数没被传递或没被赋值时返回 {@code long} 类型的 0L。
	 *
	 * @param request 当前Web应用的 {@code HttpServletRequest} 对象。
	 * @param name 获取的参数的名称。
	 * @return 返回给定参数名称的 {@code long} 类型的参数值
	 * @see #getLongParameter(HttpServletRequest, String, long)
	 */
	public static long getLongParameter(HttpServletRequest request, String name) {
		return getLongParameter(request, name, 0L);
	}

	/**
	 * 从 {@code javax.servlet.http.HttpServletRequest} 的请求中获取给定参数名称的
	 * {@code long} 类型的参数值。
	 *
	 * @param request 当前Web应用的 {@code HttpServletRequest} 对象。
	 * @param name 获取的参数的名称。
	 * @param defaultValue 该参数没被传递或没被赋值时返回的默认值。
	 * @return 返回给定参数名称的 {@code long} 类型的参数值
	 */
	public static long getLongParameter(HttpServletRequest request, String name, long defaultValue) {
		return NumberUtils.parseLong(getParameter(request, name), defaultValue);
	}

	/**
	 * 从 {@code javax.servlet.http.HttpServletRequest} 的请求中获取给定参数名称的
	 * {@code short} 类型的参数值。若该参数没被传递或没被赋值时返回 {@code short} 类型的 0。
	 *
	 * @param request 当前Web应用的 {@code HttpServletRequest} 对象。
	 * @param name 获取的参数的名称。
	 * @return 返回给定参数名称的 {@code short} 类型的参数值
	 * @see #getShortParameter(HttpServletRequest, String, short)
	 */
	public static short getShortParameter(HttpServletRequest request, String name) {
		return getShortParameter(request, name, (short) 0);
	}

	/**
	 * 从 {@code javax.servlet.http.HttpServletRequest} 的请求中获取给定参数名称的
	 * {@code short} 类型的参数值。
	 *
	 * @param request 当前Web应用的 {@code HttpServletRequest} 对象。
	 * @param name 获取的参数的名称。
	 * @param defaultValue 该参数没被传递或没被赋值时返回的默认值。
	 * @return 返回给定参数名称的 {@code short} 类型的参数值
	 */
	public static short getShortParameter(HttpServletRequest request, String name, short defaultValue) {
		return NumberUtils.parseShort(getParameter(request, name), defaultValue);
	}

	/**
	 * 获取当前 {@code javax.servlet.http.HttpServletRequest} 的请求中或者 在
	 * {@code javax.servlet.http.HttpSession} 中找到给定参数名称的属性值。若属性值不存在
	 * 则返回空字符串（&quot;&quot;）。
	 *
	 * @param request 当前Web应用的 {@code HttpServletRequest} 请求对象。
	 * @param name 获取的参数的名称。
	 * @return 返回给定参数名称的属性值。查找顺序 request、session。
	 */
	public static String getAttribute(HttpServletRequest request, String name) {
		return getAttribute(request, name, StringUtils.EMPTY);
	}

	/**
	 * 获取当前 {@code javax.servlet.http.HttpServletRequest} 的请求中或者 在
	 * {@code javax.servlet.http.HttpSession} 中找到给定参数名称的属性值。若属性值不存在 则返回给定的默认值。
	 *
	 * @param request 当前Web应用的 {@code HttpServletRequest} 请求对象。
	 * @param name 获取的参数的名称。
	 * @param defaultValue 该属性不存在或为 {@code NULL} 时返回的默认值。
	 * @return 返回给定参数名称的属性值。查找顺序 request、session。
	 */
	public static String getAttribute(HttpServletRequest request, String name, String defaultValue) {
		return getAttribute(request, name, new TypeClass<String>() {
		}, defaultValue);
	}

	/**
	 * 获取当前 {@code javax.servlet.http.HttpServletRequest} 的请求中或者 在
	 * {@code javax.servlet.http.HttpSession} 中找到给定参数名称的属性值。若属性值不存在 则返回 0。
	 *
	 * @param request 当前Web应用的 {@code HttpServletRequest} 请求对象。
	 * @param name 获取的参数的名称。
	 * @return 返回给定参数名称的属性值。查找顺序 request、session。
	 */
	public static int getIntAttribute(HttpServletRequest request, String name) {
		return getIntAttribute(request, name, 0);
	}

	/**
	 * 获取当前 {@code javax.servlet.http.HttpServletRequest} 的请求中或者 在
	 * {@code javax.servlet.http.HttpSession} 中找到给定参数名称的属性值。若属性值不存在 则返回给定的默认值。
	 *
	 * @param request 当前Web应用的 {@code HttpServletRequest} 请求对象。
	 * @param name 获取的参数的名称。
	 * @param defaultValue 该属性不存在或为 {@code NULL} 时返回的默认值。
	 * @return 返回给定参数名称的属性值。查找顺序 request、session。
	 */
	public static int getIntAttribute(HttpServletRequest request, String name, int defaultValue) {
		return getAttribute(request, name, new TypeClass<Integer>() {
		}, 0);
	}

	/**
	 * 获取当前 {@code javax.servlet.http.HttpServletRequest} 的请求中或者 在
	 * {@code javax.servlet.http.HttpSession} 中找到给定参数名称的属性值。若属性值不存在 则返回 0。
	 *
	 * @param request 当前Web应用的 {@code HttpServletRequest} 请求对象。
	 * @param name 获取的参数的名称。
	 * @return 返回给定参数名称的属性值。查找顺序 request、session。
	 */
	public static long getLongAttribute(HttpServletRequest request, String name) {
		return getLongAttribute(request, name, 0L);
	}

	/**
	 * 获取当前 {@code javax.servlet.http.HttpServletRequest} 的请求中或者 在
	 * {@code javax.servlet.http.HttpSession} 中找到给定参数名称的属性值。若属性值不存在 则返回给定的默认值。
	 *
	 * @param request 当前Web应用的 {@code HttpServletRequest} 请求对象。
	 * @param name 获取的参数的名称。
	 * @param defaultValue 该属性不存在或为 {@code NULL} 时返回的默认值。
	 * @return 返回给定参数名称的属性值。查找顺序 request、session。
	 */
	public static long getLongAttribute(HttpServletRequest request, String name, long defaultValue) {
		return getAttribute(request, name, new TypeClass<Long>() {
		}, 0L);
	}

	/**
	 * 获取当前 {@code javax.servlet.http.HttpServletRequest} 的请求中或者 在
	 * {@code javax.servlet.http.HttpSession} 中找到给定参数名称的属性值。若属性值不存在 则返回 0。
	 *
	 * @param request 当前Web应用的 {@code HttpServletRequest} 请求对象。
	 * @param name 获取的参数的名称。
	 * @return 返回给定参数名称的属性值。查找顺序 request、session。
	 */
	public static short getShortAttribute(HttpServletRequest request, String name) {
		return getShortAttribute(request, name, (short) 0);
	}

	/**
	 * 获取当前 {@code javax.servlet.http.HttpServletRequest} 的请求中或者 在
	 * {@code javax.servlet.http.HttpSession} 中找到给定参数名称的属性值。若属性值不存在 则返回给定的默认值。
	 *
	 * @param request 当前Web应用的 {@code HttpServletRequest} 请求对象。
	 * @param name 获取的参数的名称。
	 * @param defaultValue 该属性不存在或为 {@code NULL} 时返回的默认值。
	 * @return 返回给定参数名称的属性值。查找顺序 request、session。
	 */
	public static short getShortAttribute(HttpServletRequest request, String name, short defaultValue) {
		return getAttribute(request, name, new TypeClass<Short>() {
		}, (short) 0);
	}

	/**
	 * 获取当前 {@code javax.servlet.http.HttpServletRequest} 的请求中或者 在
	 * {@code javax.servlet.http.HttpSession} 中找到给定参数名称的属性值。若属性值不存在 则返回给定的默认值。
	 *
	 * @param request 当前Web应用的 {@code HttpServletRequest} 请求对象。
	 * @param name 获取的参数的名称。
	 * @param defaultValue 该属性不存在或为 {@code NULL} 时返回的默认值。
	 * @return 返回给定参数名称的属性值。查找顺序 request、session。
	 */
	public static List<String> getListAttribute(HttpServletRequest request, String name, List<String> defaultValue) {
		return getAttribute(request, name, new TypeClass<List<String>>() {
		}, defaultValue);
	}

	/**
	 * 获取当前 {@code javax.servlet.http.HttpServletRequest} 中或者在
	 * {@code javax.servlet.http.HttpSession} 中找到给定参数名称的属性值。若属性值不存在
	 * 则返回给定的默认值。属性值的类型由 {@code clazz} 指定。
	 *
	 * @param <T> 指定要转换的属性值类型。
	 * @param request 当前Web应用的 {@code HttpServletRequest} 请求对象。
	 * @param name 获取的参数的名称。
	 * @param type 要从 {@code HttpServletRequest} 请求对象中获得的属性的类型。
	 * @param defaultValue 该属性不存在或为 {@code NULL} 时返回的默认值。
	 * @return 返回给定参数名称的属性值。查找顺序 request、session。
	 */
	@SuppressWarnings("unchecked")
	public static <T> T getAttribute(HttpServletRequest request, String name, TypeClass<T> type, T defaultValue) {
		long start = System.currentTimeMillis();
		if (StringUtils.isNullStr(name))
			return defaultValue;
		Object val = request.getAttribute(name);
		if (val == null) {
			HttpSession session = request.getSession();
			if (session != null)
				val = session.getAttribute(name);
		}
		if (val == null)
			val = defaultValue;
		T result = null;
		try {
			result = ((Class<T>) type.getRawType()).cast(val);
		} catch (ClassCastException e) {
			log.warn("类型 " + type.getRawType().getName() + " 转换错误！");
			result = defaultValue;
		}
		log.debug("getAttribute(HttpServletRequest, String, TypeClass<T>, T) \n" + "(类型：" + type.getRawType().getName()
				+ ")方法执行时间 " + (System.currentTimeMillis() - start));
		return result;
	}

	/**
	 * 重新获得在 {@code HttpServletRequest} 或 {@code Cookie} 中保存的值。
	 *
	 * @param request 当前Web应用的 {@code HttpServletRequest} 请求对象。
	 * @param response 当前Web应用的 {@code HttpServletResponse} 服务器响应对象。
	 * @param key 给定的键。
	 * @param isDecrypt 取出的值是否要解密。
	 * @return 在 {@code HttpServletRequest} 或 {@code Cookie} 中保存的值。
	 */
	public static String retrieve(HttpServletRequest request, HttpServletResponse response, String key,
			boolean... isDecrypt) {
		String value = (String) request.getAttribute(key);
		if (StringUtils.isNullStr(value) || "null".equalsIgnoreCase(value)) {
			value = getCookieValue(request, key, isDecrypt);
		}
		return value;
	}

	/**
	 * 在 {@code HttpServletRequest} 或 {@code Cookie} 中保存给定的键值对。
	 *
	 * @param request 当前Web应用的 {@code HttpServletRequest} 请求对象。
	 * @param response 当前Web应用的 {@code HttpServletResponse} 服务器响应对象。
	 * @param name 保存的值的唯一名称。
	 * @param value 保存的对应于名称的值。
	 * @param domains 保存 {@code Cookie} 时指定的一个或一组域。
	 */
	public static void store(HttpServletRequest request, HttpServletResponse response, String name, String value,
			String... domains) {
		store(request, response, name, value, 0, domains);
	}

	/**
	 * 在 {@code HttpServletRequest} 中保存给定的键值对，若给定的保存周期 {@code storeTime} 大于0，
	 * 则同时保存到客户端 {@code Cookie} 中。
	 *
	 * @param request 当前Web应用的 {@code HttpServletRequest} 请求对象。
	 * @param response 当前Web应用的 {@code HttpServletResponse} 服务器响应对象。
	 * @param name 保存的值的唯一名称。
	 * @param value 保存的对应于名称的值。
	 * @param saveTime 存入 {@code Cookie} 的周期，单位：秒(s)。
	 * @param domains 保存 {@code Cookie} 时指定的一个或一组域。
	 */
	public static void store(HttpServletRequest request, HttpServletResponse response, String name, String value,
			int saveTime, String... domains) {
		if (StringUtils.isNullStr(name))
			return;
		request.setAttribute(name, value);
		if (saveTime > 0) { // 需要保存到Cookie中
			if (ArrayUtils.isNotEmpty(domains)) {
				for (String domain : domains) {
					saveCookie(response, name, value, saveTime, domain);
				}
			}
		}
	}

	/**
	 * 删除存储的值，该值可能保存于 {@code HttpServletRequest} 或 {@code Cookie} 中。 若要删除的给定键
	 * {@code name} 为空，则不作任何处理。
	 *
	 * @param request 当前Web应用的 {@code HttpServletRequest} 请求对象。
	 * @param response 当前Web应用的 {@code HttpServletResponse} 服务器响应对象。
	 * @param name 要删除的值的给定键。
	 * @param domains {@code Cookie} 值保存的域，该域可能存在多个。
	 */
	public static void delete(HttpServletRequest request, HttpServletResponse response, String name, String... domains) {
		if (StringUtils.isNullStr(name))
			return;
		request.removeAttribute(name);
		// 删除所有有关域下的给定键的值。
		if (domains != null && domains.length > 0) {
			for (String domain : domains) {
				deleteCookie(response, name, domain);
			}
		}
	}

	/**
	 * 删除给定键的 {@code Cookie} 值。{@code name} 为 {@code null} 或者空字符串，则不作任何操作。
	 *
	 * @param response 当前Web应用的 {@code HttpServletResponse} 服务器响应对象。
	 * @param name 要删除的 {@code Cookie} 键名。
	 */
	public static void deleteCookie(HttpServletResponse response, String name, String domain) {
		Cookie cookie = new Cookie(name, StringUtils.EMPTY);
		// 当用户关闭浏览器时删除Cookie的值
		if (!StringUtils.isNullStr(domain))
			cookie.setDomain(domain);
		cookie.setMaxAge(-1);
		cookie.setPath("/");
		response.addCookie(cookie);
	}

	/**
	 * 在客户端 {@code Cookie} 中保存给定的键值对，保存的值的周期由 {@code saveTime} 指定，单位：秒(s)。
	 * 默认的保存周期为一小时。
	 *
	 * @param response 当前Web应用的 {@code HttpServletResponse} 服务器响应对象。
	 * @param name 保存的 {@code Cookie} 的值的唯一名称。
	 * @param value 存的 {@code Cookie} 的对应于名称的值。
	 * @param domain {@code Cookie} 保存的域。
	 * @param isEncrypt 是否用默认的加密/解密方式加密 {@code Cookie} 的值。
	 */
	public static void saveCookie(HttpServletResponse response, String name, String value, String domain,
			boolean... isEncrypt) {
		saveCookie(response, name, value, 60 * 60, domain, isEncrypt);
	}

	/**
	 * 在客户端 {@code Cookie} 中保存给定的键值对，保存的值的周期由 {@code saveTime} 指定，单位：秒(s)。
	 *
	 * @param response 当前Web应用的 {@code HttpServletResponse} 服务器响应对象。
	 * @param name 保存的 {@code Cookie} 的值的唯一名称。
	 * @param value 保存的 {@code Cookie} 的对应于名称的值。
	 * @param saveTime {@code Cookie} 保存的周期(单位：秒) -1 - 关闭浏览器即失效。
	 * @param domain {@code Cookie} 保存的域。
	 * @param isEncrypt 是否用默认的加密/解密方式加密 {@code Cookie} 的值。
	 */
	public static void saveCookie(HttpServletResponse response, String name, String value, int saveTime, String domain,
			boolean... isEncrypt) {
		if (value == null)
			value = StringUtils.EMPTY;
		// TODO: 这里将待 StringUtils#encryptCookie 方法完成后加入代码
		// if(isEncrypt != null && isEncrypt.length > 0) {
		// if(isEncrypt[0])
		// value = StringUtils.encryptCookie(value);
		// }
		Cookie cookie = new Cookie(name, value);
		cookie.setDomain(domain);
		cookie.setMaxAge(saveTime);
		cookie.setPath("/");
		cookie.setSecure(false);
		response.addCookie(cookie);
	}

	/**
	 * 保存一组给定的 {@code Cookie}。
	 * <ul>
	 * <li>若其中 {@code Cookie} 中的 {@code name} 和 {@code value} 属性为空，则该项
	 * {@code Cookie} 不会进行保存；</li>
	 * <li>若其中 {@code Cookie} 中的 {@code path} 属性为空，则默认为 &quot;/&quot;；</li>
	 * <li>若其中 {@code Cookie} 中的 {@code secure} 属性为 {@code true}，则只能在
	 * {@code HTTPS} 下才能发送保存；</li>
	 * </ul>
	 *
	 * @param response 当前Web应用的 {@code HttpServletResponse} 服务器响应对象。
	 * @param cookies 要保存的一组 {@code Cookie}。
	 */
	public static void saveCookies(HttpServletResponse response, List<Cookie> cookies) {
		if (CollectionUtils.isEmpty(cookies)) {
			log.warn("要保存的 cookies(List<Cookie>) 是空的！");
			return;
		}
		StringBuilder warnMessages = new StringBuilder();
		for (int i = 0, len = cookies.size(); i < len; i++) {
			Cookie c = cookies.get(i);
			if (c != null && !StringUtils.isNullStr(c.getName()) && !StringUtils.isNullStr(c.getValue())) {
				if (StringUtils.isNullStr(c.getPath()))
					c.setPath("/");
				response.addCookie(c);
			} else {
				warnMessages.append("\ncookies(List<Cookie>) 中索引为 ");
				warnMessages.append(i).append(" 的 Cookie 未设置 name 或者 value，保存失败！");
			}
		}
		if (warnMessages.length() > 0) {
				log.warn(warnMessages.toString());
		}
	}

	/**
	 * 保存一组给定的 {@code Cookie}。具体请参见
	 * {@link #saveCookies(HttpServletResponse, List)}。
	 *
	 * @param response 当前Web应用的 {@code HttpServletResponse} 服务器响应对象。
	 * @param cookies 要保存的一组 {@code Cookie}。
	 */
	public static void saveCookies(HttpServletResponse response, Cookie... cookies) {
		if (cookies != null && cookies.length > 0) {
			List<Cookie> cookieList = new LinkedList<Cookie>();
			for (Cookie c : cookies) {
				cookieList.add(c);
			}
			saveCookies(response, cookieList);
		}
	}

	/**
	 * 获取给定键的 {@code Cookie} 值。若给定的 {@code Cookie} 的 {@code name} 不存在， 则返回
	 * {@code null}。
	 *
	 * @param request 当前Web应用的 {@code HttpServletRequest} 请求对象。
	 * @param name 给定的 {@code Cookie} 的键值。
	 * @param isDecrypt 取出的值是否要解密。
	 * @return 返回给定键的 {@code Cookie} 值。
	 */
	public static String getCookieValue(HttpServletRequest request, String name, boolean... isDecrypt) {
		Cookie cookie = getCookie(request, name);
		if (cookie == null)
			return null;
		String value = cookie.getValue();
		// TODO: 待StringUtils的decryptCookie方法完成之后
		// if(isNotEmpty(isDecrypt)) {
		// value = StringUtils.decryptCookie(value);
		// }
		return value;
	}
	/***  
     * 获取URI的路径,如路径为http://www.babasport.com/action/post.htm?method=add, 得到的值为"/action/post.htm"  
     * @param request  
     * @return  
     */  
    public static String getRequestURI(HttpServletRequest request){        
        return request.getRequestURI();   
    }   
    /**  
     * 获取完整请求路径(含内容路径及请求参数)  
     * @param request  
     * @return  
     */  
    public static String getRequestURIWithParam(HttpServletRequest request){        
        return getRequestURI(request) + (request.getQueryString() == null ? "" : "?"+ request.getQueryString());   
    }  
	/**
	 * 获取给定键值的 {@code Cookie}。若给定的 {@code Cookie} 键不存在，则返回 {@code null}。
	 *
	 * @param request 当前Web应用的 {@code HttpServletRequest} 请求对象。
	 * @param name 给定的 {@code Cookie} 的键值。
	 * @return 返回给定键的 {@code Cookie} 对象。
	 */
	public static Cookie getCookie(HttpServletRequest request, String name) {
		Cookie[] cookies = request.getCookies(); // 获得Cookie的集合
		if (cookies == null || StringUtils.isNullStr(name))
			return null;
		for (int i = 0; i < cookies.length; i++) {
			if (name.equals(cookies[i].getName())) {
				return cookies[i];
			}
		}
		return null;
	}

}
